package com.finalproject.entity;

/**
 * representation class of CardHolderDatabase
 */
import java.io.File;
import java.io.IOException;
import java.io.Serializable;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Scanner;

import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;

public class CardHolderDatabase implements Serializable {
	Gson gson=new Gson();
	public interface CardHolderDatabaseObserver {
		public void onLogin(CardHolder cardHolder, Integer familyId);
		public void onLogout(CardHolder cardHolder, Integer familyId);
		
	}
	
	public List<CardHolderDatabaseObserver> cardHolderDatabaseObservers;
	
	
	/////NOTE: remove by id?

	private List<CardHolder> cardHolders;
		
	
	private static CardHolderDatabase INSTANCE;
	
	public static CardHolderDatabase getInstance() {
		if(INSTANCE == null) {
			INSTANCE = new CardHolderDatabase();
		}
		return INSTANCE;
	}
	
	private CardHolderDatabase() {
		this.cardHolders = new ArrayList<CardHolder>();
		this.cardHolderDatabaseObservers = new ArrayList<CardHolderDatabaseObserver>();
		//initFromMemory();
		
		try{
		initFromFile();
		}
		catch (IOException e){
			e.printStackTrace();
		}
		
	}
	
	//"ID_"+doeFamily.getId()+".txt"
	
	private void initFromFile() throws IOException{
		String str=readFile("ID_123456.txt");
		cardHolders.add(gson.fromJson(str, CardHolder.class));
		str=readFile("ID_234567.txt");
		cardHolders.add(gson.fromJson(str, CardHolder.class));
		str=readFile("ID_345678.txt");
		cardHolders.add(gson.fromJson(str, CardHolder.class));
	}
	private String readFile(String pathname) throws IOException {

	    File file = new File(pathname);
	    StringBuilder fileContents = new StringBuilder((int)file.length());
	    Scanner scanner = new Scanner(file);
	    String lineSeparator = System.getProperty("line.separator");

	    try {
	        while(scanner.hasNextLine()) {        
	            fileContents.append(scanner.nextLine() + lineSeparator);
	        }
	        return fileContents.toString();
	    } finally {
	        scanner.close();
	    }
	}
	
	public List<CardHolder> getCardHolders() {
		return cardHolders;
	}
	
	public CardHolder getIndex(int index) {
		return cardHolders.get(index);
	}
	
	private void initFromMemory() {
		
		CardHolder doeFamily=new CardHolder(123456,1234);

		doeFamily.addMember("John Doe", 01);	
		//john is a multiuser cardholder

		doeFamily.addMember("Jane Doe", 02);	
		cardHolders.add(doeFamily);
		
		//jane is a multiuser cardholder
		
		CardHolder mojo=new CardHolder(234567, 1234);
		mojo.addMember("Mojo Risin", 00);	
		cardHolders.add(mojo);
		//Mr. Mojo Risin is a regular cardholder
		
		CardHolder ziggy=new CardHolder(345678, 1234);
		ziggy.addMember("Ziggy Stardust", 00);
		cardHolders.add(ziggy);
		
		
		
	}
	
	
	
	public void add(CardHolder CardHolder) {
		cardHolders.add(CardHolder);
	}
	
	
	public void remove(CardHolder CardHolder) {
		cardHolders.remove(CardHolder);
	}
	
	
	
	
	public void authenticate(int myId, int myPinCode, Integer familyId) throws InvalidCardHolderException{
		if(familyId == null) {
			familyId = 00;
		}
		for(CardHolder cardHolder: cardHolders) {
			int id = cardHolder.getId();
			int pinCode = cardHolder.getPincode();
			if(id == myId && pinCode == myPinCode) {
				
				
				Map<Integer,String> nameMap = cardHolder.getNameMap();
				String name = nameMap.get(familyId);
				if(name != null) {
					cardHolder.selectCurrentMember(familyId);
					fireCardHolderDatabaseObserverOnLogin(cardHolder,familyId);
					
					return;
				}
				
				
			} 
			
		}
		throw new InvalidCardHolderException();
		
	}
	
	
	public void logout(CardHolder cardHolder, Integer familyId) {
		cardHolder.logout(familyId);
		
		fireCardHolderDatabaseObserverOnLogOut(cardHolder,familyId);
	}
	
	public void addCardHolderDatabaseObserver(CardHolderDatabaseObserver cardHolderDatabaseObserver) {
		cardHolderDatabaseObservers.add(cardHolderDatabaseObserver);
	}
	
	
	public void removeCardHolderDatbaseObserver(CardHolderDatabaseObserver carHolderDatabaseObserver) {
		cardHolderDatabaseObservers.remove(carHolderDatabaseObserver);
	}
	
	
	

	private void fireCardHolderDatabaseObserverOnLogOut(CardHolder cardHolder, Integer familyId) {
		for(CardHolderDatabaseObserver cardHolderDatabaseObserver: cardHolderDatabaseObservers) {
			cardHolderDatabaseObserver.onLogout(cardHolder, familyId);
		}
	}
	
	
	private void fireCardHolderDatabaseObserverOnLogin(CardHolder cardHolder, Integer familyId) {
		for(CardHolderDatabaseObserver cardHolderDatabaseObserver: cardHolderDatabaseObservers) {
			cardHolderDatabaseObserver.onLogin(cardHolder,familyId);
		}
	}
	
	public class InvalidCardHolderException extends Exception {
		public InvalidCardHolderException() {
			
		}
	}
	
	
	
}
